package com.openatc.agent.service.impl;

import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import com.openatc.agent.model.Interfeature;
import com.openatc.agent.model.Route;
import com.openatc.agent.model.RouteIntersection;
import com.openatc.agent.service.AscsDao;
import com.openatc.agent.service.RouteDao;
import com.openatc.agent.service.RouteService;
import com.openatc.comm.data.MessageData;
import com.openatc.model.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @Classname RouteServiceImpl
 * @Description
 * @Date 2022/11/21 17:55
 * @Created by panleilei
 */
@Service
public class RouteServiceImpl implements RouteService {

    private Gson gson = new GsonBuilder().create();
    @Autowired
    private RouteDao routeDao;
    @Autowired
    private AscsDao ascsDao;

    @Override
    public List<String> getAgentIds(JsonArray devJsonArray) {
        List<RouteIntersection> devs = gson.fromJson(devJsonArray,new TypeToken<List<RouteIntersection>>(){}.getType());
        List<String> agentIds = new ArrayList<>();
        if (CollectionUtils.isEmpty(devs)) {
            return agentIds;
        }

        for (RouteIntersection dev : devs) {
            agentIds.add(dev.getAgentid());
        }
        return agentIds;
    }

    @Override
    public Map<String, Feature> getCrossFeature(List<MessageData> messageDatas) {
        Map<String,Feature> featureMap = new HashMap<>();
        for (MessageData messageData : messageDatas) {
            featureMap.put(messageData.getAgentid(),gson.fromJson(messageData.getData(),Feature.class));
        }
        return featureMap;
    }

    @Override
    public List<MessageData> buildFeatureStructure(Map<String, Feature> featureMap, JsonArray optPatternList, String routeName) {
        JsonElement pattern = optPatternList.get(0);
        // 协调方案名称
        String patternTitle = pattern.getAsJsonObject().get("title").getAsString();
        // 新建方案名称
        String newPatternName = routeName + "-" + patternTitle;
        List<Integer> month = gson.fromJson(pattern.getAsJsonObject().get("month").getAsJsonArray(),new TypeToken<List<Integer>>(){}.getType());
        List<Integer> day = gson.fromJson(pattern.getAsJsonObject().get("day").getAsJsonArray(),new TypeToken<List<Integer>>(){}.getType()) ;
        List<Integer> date = gson.fromJson(pattern.getAsJsonObject().get("date").getAsJsonArray(),new TypeToken<List<Integer>>(){}.getType());
        JsonElement plan = pattern.getAsJsonObject().get("plan");
        JsonArray devJsonArray = optPatternList.get(0).getAsJsonObject().get("devs").getAsJsonArray();
        List<RouteIntersection> devs = gson.fromJson(devJsonArray,new TypeToken<List<RouteIntersection>>(){}.getType());

        List<MessageData> messageDatas = new ArrayList<>();

        for (RouteIntersection dev : devs) {
            // 当前路口不参与协调
            if (!dev.isIsused()) continue;
            String agentId = dev.getAgentid();
            // 信号机当前的配置
            Feature originalFeature = featureMap.get(agentId);
            if (originalFeature == null) continue;
            Interfeature feature = dev.getFeature();
            // 干线协调界面选中的方案id
            int selectedPatternId = dev.getPatternid();
            // 最终的方案id
            int finalPatternId = createFinalPatternId(originalFeature.getPatternList(),newPatternName);
            // 构建方案列表
            List<Pattern> patternList = buildPatternList(originalFeature.getPatternList(),feature.getPatternList(),newPatternName,finalPatternId,selectedPatternId);
            // 下发方案参数
            messageDatas.add(buildPatternMessageData(agentId,patternList));
            // 只有月份、时段起始、时段结束这几个参数都存在时，才下发时段和日期参数
            String start = "";
            if (plan.getAsJsonObject().has("start")) {
                start = plan.getAsJsonObject().get("start").getAsString();
            }
            String end = "";
            if (plan.getAsJsonObject().has("end")) {
               end = plan.getAsJsonObject().get("end").getAsString();
            }
            if (!CollectionUtils.isEmpty(month) && StringUtils.hasLength(start) && StringUtils.hasLength(end)) {
                // 下发计划参数
                Map<Integer, MessageData> planData = buildFeaturePlan(plan, originalFeature, finalPatternId, newPatternName, agentId);
                Integer planid = 1;
                for (Integer key : planData.keySet()) {
                    planid = key;
                }
                messageDatas.add(planData.get(planid));
                // 下发日期参数
                messageDatas.add(buildFeatureDate(planid, date, day, month, newPatternName, originalFeature,agentId));
            }

        }

        return messageDatas;
    }


    /**
     * @param patternList 信号机原始的方案列表
     * @param newPatternList  干线协调下发的方案列表
     * @param newPatternName  干线协调下发的方案名称
     * @param finalPatternId  最终的方案id
     * @param selectedPatternId   干线协调界面选中的方案id
     * @return
     */
    private List<Pattern> buildPatternList(List<Pattern> patternList, JsonElement newPatternList, String newPatternName, int finalPatternId, int selectedPatternId) {
        List<Pattern> patterns = gson.fromJson(newPatternList,new TypeToken<List<Pattern>>(){}.getType());
        // 如果信号机当前的方案列表中包含最终需要下发方案的id，则无需新增方案，替换原来的方案
        int finalPatternIndex = -1;
        for (Pattern pattern : patternList) {
            if (finalPatternId == pattern.getId()) {
                finalPatternIndex = patternList.indexOf(pattern);
                break;
            }
        }
        if (finalPatternIndex != -1) {
            // 移除原有的方案
            patternList.remove(finalPatternIndex);
            // 干线协调的方案替换原有的方案
            for (Pattern pattern : patterns) {
                if (selectedPatternId == pattern.getId()) {
                    pattern.setDesc(newPatternName);
                    pattern.setId(finalPatternId);
                    patternList.add(finalPatternIndex,pattern);
                    break;
                }
            }
            return patternList;
        }
        // 信号机列表中不包含最终需要下发方案的id，则新增方案
        else {
            for (Pattern pattern : patterns) {
                if (selectedPatternId == pattern.getId()) {
                    pattern.setDesc(newPatternName);
                    pattern.setId(finalPatternId);
                    patternList.add(pattern);
                    break;
                }
            }
        }

        return patternList;
    }

    /**
     * 确认最终的方案编号
     * @param patternList
     * @param newPatternName
     * @return
     */
    private int createFinalPatternId(List<Pattern> patternList, String newPatternName) {
        if (CollectionUtils.isEmpty(patternList)) return 0;
        int maxPatternId = patternList.get(0).getId();
        for (Pattern pattern : patternList) {
            if (newPatternName.equals(pattern.getDesc())) {
                return pattern.getId();
            }
            if (pattern.getId() > maxPatternId) {
                maxPatternId = pattern.getId();
            }
        }
        return maxPatternId + 1;
    }


    /**
     * 更新协调线路中的方案列表
     * @param routeEntity
     * @param dbRoute
     * @return
     */
    public Route updatePatternList(Route routeEntity, Route dbRoute) {
        // 数据库中保存的方案
        JsonArray dbOptPatternList = dbRoute.getOptPatternList();
        // 前端下发的方案
        JsonArray optPatternList = routeEntity.getOptPatternList();
        if (dbOptPatternList == null) {
            dbRoute.setOptPatternList(optPatternList);
        } else {
            int patternIndex = 0;
            boolean needRemove = false;
            int patternId = optPatternList.get(0).getAsJsonObject().get("id").getAsInt();
            for (JsonElement pattern : dbOptPatternList) {
                int dbPatternId = pattern.getAsJsonObject().get("id").getAsInt();
                if (dbPatternId == patternId) {
                    needRemove = true;
                    break;
                }
                patternIndex++;
            }
            if (needRemove) {
                dbOptPatternList.set(patternIndex,optPatternList.get(0));
            } else {
                dbOptPatternList.add(optPatternList.get(0));
            }
        }
        return dbRoute;
    }

    @Override
    public JsonElement getNeedRemovePattern(int patternid, JsonArray optPatternList) {
        for (JsonElement pattern : optPatternList) {
            int dbPatternId = pattern.getAsJsonObject().get("id").getAsInt();
            if (patternid == dbPatternId) {
                return pattern;
            }
        }
        return null;
    }

    @Override
    public List<Route> getRouteList(Sort sort) {
        List<Route> routes = routeDao.findAll(sort);
        for (Route route : routes) {
            Set<RouteIntersection> devs = route.getDevs();
            if (!CollectionUtils.isEmpty(devs)) {
                for (RouteIntersection dev : devs) {
                    String agentId = dev.getAgentid();
                    AscsBaseModel ascsBaseModel = ascsDao.getAscsByID(agentId);
                    if(ascsBaseModel == null) continue;
                    dev.setName(ascsBaseModel.getName());
                }
            }
        }
        return routes;
    }

    /**
     * 构建方案参数
     * @param patternList  需要下发给信号机的方案列表
     * @param agentid   路口id
     * @return
     */
    private MessageData buildPatternMessageData(String agentid, List<Pattern> patternList) {

        MessageData messageData = new MessageData();
        messageData.setAgentid(agentid);
        messageData.setOperation("set-request");
        messageData.setInfotype("feature/pattern");

        JsonObject jsonObject = new JsonObject();
        jsonObject.add("patternList",gson.toJsonTree(patternList));

        messageData.setData(jsonObject);
        return messageData;
    }

    /**
     * 构建计划参数
     * @param plan
     * @param feature
     * @param patternid
     * @param agentid
     * @param name
     * @return
     */
    private Map<Integer, MessageData> buildFeaturePlan(JsonElement plan, Feature feature, int patternid, String name, String agentid) {
        List<Plan> planList = feature.getPlanList();
        Integer planid;
        boolean needNewPlan = true; // 是否需要新建计划
        int index = 0;
        for (Plan plan1 : planList) {
            if (name.equals(plan1.getDesc())) { // 无需新建计划
                needNewPlan = false;
                break;
            }
            index++;
        }
        // 新建计划
        if (needNewPlan) {
            int maxPlanId = computeMaxPlanId(planList);
            int newPlanid = maxPlanId + 1;
            planid = newPlanid;
            Plan newPlan = new Plan();
            newPlan.setId(newPlanid);
            newPlan.setDesc(name);
//            newPlan.setCoorDination(1);
            newPlan.setCoordinate(1);
            newPlan.setPlan(getPlan(patternid,plan));
            planList.add(newPlan);
        } else {
            Plan plan1 = planList.get(index);
            planid = plan1.getId();
//            plan1.setCoorDination(1);
            plan1.setCoordinate(1);
            plan1.setPlan(getPlan(patternid,plan));
        }

        MessageData messageData = new MessageData();
        messageData.setAgentid(agentid);
        messageData.setOperation("set-request");
        messageData.setInfotype("feature/plan");

        JsonObject jsonObject = new JsonObject();
        jsonObject.add("planList",gson.toJsonTree(planList));
        messageData.setData(jsonObject);

        Map<Integer,MessageData> map = new HashMap<>();
        map.put(planid,messageData);
        return map;
    }


    /**
     * 构建日期参数
     * @param planid
     * @param date
     * @param day
     * @param month
     * @param name
     * @param feature
     * @param agentid
     * @return
     */
    private MessageData buildFeatureDate(Integer planid, List<Integer> date, List<Integer> day, List<Integer> month, String name, Feature feature, String agentid) {

        List<DateParam> dateList = feature.getDateList();
        boolean needNewDate = true; // 是否需要新建日期
        int index = 0;
        for (DateParam dateParam : dateList) {
            if (name.equals(dateParam.getDesc())) { // 无需新建计划
                needNewDate = false;
                break;
            }
            index++;
        }

        if (needNewDate) {
            int maxDateId = computeMaxDateId(dateList);
            DateParam dateParam = new DateParam();
            dateParam.setId(maxDateId + 1);
            dateParam.setDesc(name);
            dateParam.setPlan(planid);
            dateParam.setDay(day);
            dateParam.setMonth(month);
            dateParam.setDate(date);
            dateList.add(0,dateParam);
        } else {
            DateParam dateParam = dateList.get(index);
            dateParam.setPlan(planid);
            dateParam.setDate(date);
            dateParam.setMonth(month);
            dateParam.setDay(day);
            dateList.add(0,dateList.remove(index));
        }


        MessageData messageData = new MessageData();
        messageData.setAgentid(agentid);
        messageData.setOperation("set-request");
        messageData.setInfotype("feature/date");

        JsonObject jsonObject = new JsonObject();
        jsonObject.add("dateList",gson.toJsonTree(dateList));
        messageData.setData(jsonObject);

        return messageData;
    }

    /**
     * 计算日期中的最大id
     * @param dateList
     * @return
     */
    private int computeMaxDateId(List<DateParam> dateList) {

        int max = 1;
        for (DateParam dateParam : dateList) {
            if (dateParam.getId() > max) {
                max = dateParam.getId();
            }
        }
        return max;
    }

    /**
     * 计划参数中的时段
     * @param patternid
     * @param plan
     * @return
     */
    private List<PlanTime> getPlan(int patternid, JsonElement plan) {
        List<PlanTime> planTimes = new ArrayList<>();
        String start = plan.getAsJsonObject().get("start").getAsString();
        String[] starts = start.split(":");
        String end = plan.getAsJsonObject().get("end").getAsString();
        String[] ends = end.split(":");

        PlanTime startTime = new PlanTime();
        startTime.setId(1);
        startTime.setControl(10);
        startTime.setHour(Integer.valueOf(starts[0]));
        startTime.setMinute(Integer.valueOf(starts[1]));
        startTime.setPattern(patternid);


        PlanTime endTime = new PlanTime();
        endTime.setId(2);
        endTime.setControl(0);
        endTime.setHour(Integer.valueOf(ends[0]));
        endTime.setMinute(Integer.valueOf(ends[1]));
        // 恢复自主控制时方案，没有方案，和前端约定给默认值
//        endTime.setPattern(0);

        planTimes.add(startTime);
        planTimes.add(endTime);

        return planTimes;
    }

    /**
     * 计算最大的计划号
     * @param planList
     * @return
     */
    private int computeMaxPlanId(List<Plan> planList) {
        int max = 1;
        for (Plan plan : planList) {
            if (plan.getId() > max) {
                max = plan.getId();
            }
        }
        return max;
    }
}
